package cn.lysj.framework.common.validate.validate;

import cn.lysj.framework.common.validate.Message;
import cn.lysj.framework.common.validate.entity.Entity;
import cn.lysj.framework.common.validate.entity.Medusa;
import cn.lysj.framework.common.validate.helper.AnnotationHelper;
import cn.lysj.framework.common.validate.reflect.ReflectUtils;
import java.lang.annotation.Annotation;
import java.util.*;

public class Validator {

    private Object object;

    private Map<String,Set<Class<? extends Annotation>>> map;

    public static Validator newInstance() {
        return new Validator();
    }

    public static Validator newInstance(Object object) {
        return new Validator(object);
    }

    public static Validator newInstance(Object object,Map<String,Set<Class<? extends Annotation>>> map) {
        return new Validator(object,map);
    }

    private Validator() {}

    private Validator(Object object) {
        this.object = object;
    }

    private Validator(Object object,Map<String,Set<Class<? extends Annotation>>> map) {
        this.object = object;
        this.map = map;
    }

    /**
     * explain: 校验方法，该方法校验整个对象的所有注解，然后返回true/false
     * @param object 待校验的对象
     * @param map 忽略的校验
     **/
    public boolean validate(Object object,Map<String,Set<Class<? extends Annotation>>> map) {
        List<Medusa> medusaSet = result(object,map);
        for (Medusa medusa : medusaSet) {
            if (!medusa.isFlag()) return false;
        }
        return true;
    }

    /**
     * explain: 校验方法，该方法校验整个对象的所有注解，然后返回true/false
     * 该方法无参，使用{@link Validator#newInstance(Object,Map)} 方法，可以直接调用此方法得到校验结果
     **/
    public boolean validate() {
        return validate(this.object,this.map);
    }

    /**
     * explain: 弹出第一个校验结果
     * 该方法无参，使用{@link Validator#newInstance(Object,Map)} 方法，可以直接调用此方法得到校验结果
     **/
    public Medusa pop() {
        return pop(this.object,this.map);
    }

    /**
     * explain: 弹出第一个校验结果
     * @param object 待校验的对象
     * @param map 忽略的校验
     **/
    public Medusa pop(Object object, Map<String,Set<Class<? extends Annotation>>> map) {
        List<Medusa> medusaSet = result(object,map);
        return medusaSet.iterator().next();
    }

    /**
     * explain: 弹出第一个错误的校验结果
     * @param object 待校验的对象
     * @param map 忽略的校验
     **/
    public Medusa popDeny(Object object, Map<String,Set<Class<? extends Annotation>>> map) {
        List<Medusa> listYes = new ArrayList<>(); //存放将排序的错误消息对象
        List<Medusa> listNo = new ArrayList<>(); //存放将不排序的错误消息对象
        List<Medusa> medusaSet = result(object,map);
        for (Medusa medusa : medusaSet) {
            if (!medusa.isFlag()) return medusa;
        }
        Message.isSort(listYes,listNo,medusaSet);
        return Message.getMedusa(listYes,listNo);
    }

    /**
     * explain: 弹出第一个错误的校验结果
     * 该方法无参，使用{@link Validator#newInstance(Object,Map)} 方法，可以直接调用此方法得到校验结果
     **/
    public Medusa popDeny() {
        return popDeny(this.object,this.map);
    }

    /**
     * explain: 获取校验返回值 该方法校验所有的注解，并返回校验结果Set<Medusa>
     * 该方法无参，使用{@link Validator#newInstance(Object,Map)} 方法，可以直接调用此方法得到校验结果
     **/
    public List<Medusa> result() {
        return result(this.object,this.map);
    }

    /**
     * explain: 获取校验返回值 该方法校验所有的注解，并返回校验结果Set<Medusa>
     *     该方法需要校验对象作为参数，使用{@link Validator#newInstance(Object)} 方法，可以直接调用此方法传入校验对象得到校验结果
     * @param object 待校验的对象
     **/
    public List<Medusa> result(Object object, Map<String,Set<Class<? extends Annotation>>> map) {
        try {
            //获取待校验对象中所有参数上的注解、参数名、参数值，返回Set集合    （注解、参数名、参数值）放在Entity类中
            Set<Entity> entitySet = ReflectUtils.getSet(object,map);
            //构建一个空的HashSet，用于存放校验返回结果
            List<Medusa> medusaSet = new ArrayList<>();
            //循环校验所有field
            for (Entity entity : entitySet) {
                //获取注解
                Annotation annotation = entity.getAnnotation();
                //获取注解的class
                Class<? extends Annotation> clazz = AnnotationHelper.choice(annotation);
                //执行注解clazz方法指向的class.result方法
                Object[] params = {entity};
                // clazz.getMethod("clazz").getDefaultValue() == class org.yxs.medusa.validate.NullValidate
                Object result = ReflectUtils.invokeMethod((Class<?>) clazz.getMethod("clazz").getDefaultValue(), "result", params);
                //将校验结果放入set
                // result ==  Medusa{flag=false, field=private java.lang.String org.yxs.Example$User.passwd, message='必须为空'}
                medusaSet.add((Medusa) result);
            }
            return medusaSet;

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

}
